﻿using System;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Description;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;

namespace Broadbeach.Core
{
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class TfsEventListener : INotificationService, IDisposable
    {
        public const string WorkItemChangedEventName = "WorkItemChangedEvent";

        private readonly object _lock = new object();
        private readonly string _eventName;
        private readonly ITfsEventProcessor _eventProcessor;
        private ServiceHost _serviceHost;
        private readonly IDictionary<IEventService, int> _subscriptions = new Dictionary<IEventService, int>();
        private readonly IDictionary<string, TfsTeamProjectCollection> _endpointCollections = new Dictionary<string, TfsTeamProjectCollection>();

        public TfsEventListener(string eventName, Uri baseAddress, IEnumerable<TfsTeamProjectCollection> collections, ITfsEventProcessor eventProcessor)
        {
            _eventName = eventName;
            _eventProcessor = eventProcessor;
            _serviceHost = new ServiceHost(this, baseAddress);
            var binding = new WSHttpBinding {Security = {Mode = SecurityMode.None}};

            var collectionEndpoints = new Dictionary<TfsTeamProjectCollection, ServiceEndpoint>();
            foreach (var collection in collections)
            {
                var endpoint = _serviceHost.AddServiceEndpoint(typeof(INotificationService), binding, Guid.NewGuid().ToString("N"));
                _endpointCollections.Add(endpoint.ListenUri.AbsoluteUri, collection);
                collectionEndpoints.Add(collection, endpoint);
            }
            _serviceHost.Open();

            foreach (var collection in collections)
            {
                var eventService = collection.GetService<IEventService>();
                var deliveryPreference = new DeliveryPreference
                {
                    Type = DeliveryType.Soap,
                    Schedule = DeliverySchedule.Immediate,
                    Address = collectionEndpoints[collection].ListenUri.AbsoluteUri
                };
                _subscriptions.Add(eventService, eventService.SubscribeEvent(_eventName, null, deliveryPreference));
            }
        }

        void INotificationService.Notify(string eventXml, string tfsIdentityXml)
        {
            var collection = _endpointCollections[OperationContext.Current.Channel.LocalAddress.Uri.AbsoluteUri];
            _eventProcessor.ProcessEvent(collection, eventXml);
        }

        public void Dispose()
        {
            ServiceHost serviceHost;
            lock (_lock)
            {
                serviceHost = _serviceHost;
                if (serviceHost == null) return;
                _serviceHost = null;
            }
            foreach (var eventService in _subscriptions.Keys)
            {
                eventService.UnsubscribeEvent(_subscriptions[eventService]);
            }
            serviceHost.Close();
        }
    }
}